/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package rna;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

/**
 *
 * @author Igo Amauri
 */

/**
 *
 * @Descrição
 * Essa classe vai trabalhar em cima do array de camadas.
 * Que utilizando o mesmo, irá efetuar o treinamento, fazendo a atualização dos pesos.
 */

public class Treinamento {
    ArrayList<Camadas> arrayCamadasDestreinada;
    Arquivo dadosArquivo = new Arquivo();
    ArrayList<double[]> arrayDados = new ArrayList<double[]>();
    double auxErroQuadratico;
    double[] erroQuadratico = new double[550];
    Rede rede;
    FeedFoward feed = new FeedFoward();

    public Treinamento(Rede redeCriada){
        rede = redeCriada;
        arrayCamadasDestreinada = rede.arrayCamadas;
    }

    public Rede treinar() throws FileNotFoundException, IOException{
        //Obter os dados do arquivo
        dadosArquivo.lerArquivo();
        arrayDados = dadosArquivo.arrayEntradas;

        double erroEpocaAnterior = Double.MAX_VALUE;
        double erroEpocaAtual = 1.0;
            
            //For para fazer uma êpoca
//            for(int i=0; i<550;i++){
//                //Primeiro passo: fazer feed.
//                if(i==0){
//                    fazerFeed(arrayDados.get(i), true);
//                }
//                else{
//                    fazerFeed(arrayDados.get(i), false);
//                }
//
//
//                //Segundo passo, Calcular erro quadratico desse padrão
//                calcularErroQuadratico(i);
//
//                //Fazer o back, calcular gradientes e atualizar pesos.
//                fazerBack(i);
//            }

//            double erroEpocaInicial = calcularErroEpoca();
//
//            erroEpocaAtual = erroEpocaInicial;
            int epocas =0;

         while (Math.abs(erroEpocaAnterior - erroEpocaAtual)  > 0.000001){
            
            erroEpocaAnterior = erroEpocaAtual;
            for(int i=0; i<550;i++){
                //Primeiro passo: fazer feed.
//                fazerFeed(arrayDados.get(i), false);
                if(i==0 && epocas==0){
                    fazerFeed(arrayDados.get(i), true);
                }
                else{
                    fazerFeed(arrayDados.get(i), false);
                }
                //Segundo passo, Calcular erro quadratico desse padrão
                calcularErroQuadratico(i);
                //Fazer o back, calcular gradientes e atualizar pesos.
                fazerBack(i);
            }

            erroEpocaAtual = calcularErroEpoca();
//            System.out.println("");
            System.out.println("Epoca: " + epocas);
            System.out.println("ERRO: " + erroEpocaAtual);
//            System.out.println("");
            epocas++;
         }

        System.out.println("------------------------");
        System.out.println("Treino Finalizado");
        System.out.println("Foram necessárias: " + epocas + " Epocas!");
        System.out.println("Critério de Parada: " + (erroEpocaAnterior - erroEpocaAtual));
        System.out.println("------------------------");

        rede.setArrayCamadas(arrayCamadasDestreinada);
        return rede;
    }

    public double calcularErroEpoca(){
        double somatorio = 0.0;


        for(int i=0; i<erroQuadratico.length;i++){
            somatorio = somatorio + erroQuadratico[i];
        }

        
        double erroEpoca = somatorio/erroQuadratico.length;
        return erroEpoca;
    }

    public void fazerFeed(double[] array, boolean flag){
        
        arrayCamadasDestreinada = feed.executarFeedfoward(arrayCamadasDestreinada, array, flag);
    }

    public void calcularErroQuadratico(int i){

//        System.out.println("");
//        System.out.println("O erro quadratico do padrão : " + i);
//        System.out.println("");

        auxErroQuadratico = dadosArquivo.arraySaidaDesejada.get(i) - rede.getSaidaUltimaCamada();
        erroQuadratico[i] = (Math.pow(auxErroQuadratico, 2)) / 2;

//            System.out.println("Desejado: " + dadosArquivo.arraySaidaDesejada.get(i));
//            System.out.println("Obtido: " + rede.getSaidaUltimaCamada());
//            System.out.println("Aux Erro quadratico é: " + auxErroQuadratico);
//        System.out.println("O Erro quadratico é: " + erroQuadratico[i]);

    }

    public void fazerBack (int i){
        BackPropagation back = new BackPropagation(arrayCamadasDestreinada, dadosArquivo.arraySaidaDesejada.get(i));
        back.executarBackPropagation();
    }
}
